<template>
    <section ref="wrap">
        <!-- 图片拖拽部分 -->
        <div
            v-drag
            class="z-10 drag"
            @click="maskClosable && handleCloseClick()"
        >
            <img
                @click.stop
                ref="img"
                :src="currentSrc"
                draggable="false"
                class="preview-img"
                :style="{
                    transformOrigin: 'center',
                    transition: 'transform 0.2s',
                    transform: `rotate(${rotate}deg) scale3d(${scaleX}, ${scaleY}, 1)`
                }"
            />
        </div>

        <!-- 蒙层 -->
        <div
            v-if="mask"
            class="mask"
            @click="maskClosable && handleCloseClick()"
            :style="{ background: maskBackground }"
        ></div>

        <!-- 操作按钮栏 -->
        <div class="operate-button">
            <template v-if="list?.length">
                <icon-caret-left
                    @click="handleSwitchBtnClick('left')"
                    class="cursor-pointer"
                />
                <div class="flex items-center flex-shrink-0 mx-5 select-none text-15">
                    {{ currentIndex + 1 }} / {{ list.length }}
                </div>
                <icon-caret-right
                    @click="handleSwitchBtnClick('right')"
                    class="cursor-pointer"
                />
            </template>
            <icon-swap
                class="rotate-90"
                @click="handleTurnBtnClick('y')"
            />
            <icon-swap @click="handleTurnBtnClick('x')" />
            <icon-rotate-left @click="rotate -= 90" />
            <icon-rotate-right @click="rotate += 90" />
            <icon-zoom-out @click="handleScaleBtnClick(-0.5)" />
            <icon-zoom-in @click="handleScaleBtnClick(0.5)" />
            <icon-original-size @click="handleRsesetClick" />
            <IconDownload @click="handleDownload" />
            <icon-close-circle @click="handleCloseClick" />
        </div>
    </section>
</template>

<script setup lang="ts">
import { ref, useTemplateRef } from 'vue'
import {
    IconCaretLeft,
    IconCaretRight,
    IconCloseCircle,
    IconOriginalSize,
    IconRotateLeft,
    IconRotateRight,
    IconZoomIn,
    IconZoomOut,
    IconSwap,
    IconDownload
} from '@arco-design/web-vue/es/icon'
import { useEventListener } from '@vueuse/core'
import type { PreviewProps } from './types.d'
import { downloadImg } from '@/utils'

const {
    src,
    list = [],
    mask = true,
    escCloseable = true,
    maskClosable = true,
    maskBackground = 'rgba(0, 0, 0, 0.45)',
    lockBodyScroll = true
} = defineProps<PreviewProps>()

// 操作按钮相关
const rotate = ref(0)
const scaleX = ref(1)
const scaleY = ref(1)
const handleScaleBtnClick = (num: number) => {
    const x = scaleX.value
    const y = scaleY.value
    if (num < 0 && Math.abs(scaleX.value) <= 0.5) return
    scaleX.value = x > 0 ? x + num : -(Math.abs(x) + num)
    scaleY.value = y > 0 ? y + num : -(Math.abs(y) + num)
}
const handleTurnBtnClick = (type: 'x' | 'y') => {
    if (type === 'x') scaleX.value = -scaleX.value
    if (type === 'y') scaleY.value = -scaleY.value
}

/**
 * 重置图片大小和旋转点击事件
 */
const handleRsesetClick = () => {
    scaleX.value = 1
    scaleY.value = 1
    rotate.value = 0
}

/**
 * 处理切换按钮点击事件
 */
const currentSrc = ref(src)
const currentIndex = ref(list.findIndex(item => item === src))
const handleSwitchBtnClick = (direction: 'left' | 'right') => {
    const len = list?.length
    const cur = currentIndex.value
    if (direction === 'right') {
        currentIndex.value = cur + 1 >= len ? 0 : ++currentIndex.value
    } else if (direction === 'left') {
        currentIndex.value = cur === 0 ? len - 1 : --currentIndex.value
    }
    currentSrc.value = list[currentIndex.value]
    handleRsesetClick()
}

const handleDownload = () => downloadImg(currentSrc.value)

/**
 * 监听键盘退出事件，ESC键可关闭
 */
let removeKeydownListener: () => void
removeKeydownListener = useEventListener(document, 'keydown', (event: KeyboardEvent) => {
    if (event.key === 'Escape' && escCloseable) handleCloseClick()
})

/**
 * 监听鼠标滚轮事件
 */
const imgRef = useTemplateRef<HTMLImageElement>('img')
let removeWheelListener: () => void
removeWheelListener = useEventListener(imgRef, 'wheel', (event: WheelEvent) => {
    event.deltaY > 0 ? handleScaleBtnClick(0.1) : handleScaleBtnClick(-0.1)
})

/**
 * 预览图片时body是否能滚动
 */
const setBodyOverflow = (value: 'hidden' | 'auto') => (document.body.style.overflow = value)
lockBodyScroll && setBodyOverflow('hidden')

/**
 * 关闭图片预览框
 */
const wrap = ref<HTMLDivElement>()
const handleCloseClick = () => {
    setBodyOverflow('auto')
    removeKeydownListener && removeKeydownListener()
    removeWheelListener && removeWheelListener()
    const parentNode = wrap.value?.parentNode as HTMLElement
    parentNode.remove()
}
</script>

<style scoped lang="less">
.drag {
    position: fixed;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
}

.preview-img {
    max-width: 800px;
    height: auto;
    animation: scale 0.1s ease-out;
    user-select: none;
}

.mask {
    animation: fade 0.1s;
    position: fixed;
    top: 0;
    left: 0;
    width: 100vw;
    height: 100vh;
}

@keyframes fade {
    from {
        opacity: 0;
    }
    to {
        opacity: 1;
    }
}

@keyframes scale {
    from {
        transform: scale(0.5);
    }
    to {
        transform: scale(1);
    }
}

.operate-button {
    position: fixed;
    display: flex;
    border-radius: 5px;
    font-size: 20px;
    background: rgba(0, 0, 0, 0.4);
    position: fixed;
    bottom: 20px;
    color: #fff;
    z-index: 1000;
    left: 50%;
    transform: translateX(-50%);
    overflow: hidden;
}

:deep(.arco-icon) {
    padding: 10px;
    cursor: pointer;

    &:hover {
        background: rgba(0, 0, 0, 0.5);
    }
}
</style>
